#include <iostream>
#include <cstring>
#include <algorithm>

int multiplex_TDM(unsigned char *c, const int c_size,
                  const unsigned char *a, const int a_len,
                  const unsigned char *b, const int b_len)
{
    if (a_len != b_len)
        return -1;
    int required = 2 * a_len;
    if (c_size < required)
        return -1;
    for (int i = 0; i < a_len; ++i)
    {
        c[2 * i] = a[i] ? 1 : 0;
        c[2 * i + 1] = b[i] ? 1 : 0;
    }
    return 0;
}

int demultiplex_TDM(unsigned char *a, const int a_size,
                    unsigned char *b, const int b_size,
                    const unsigned char *c, const int c_len)
{
    int a_len = (c_len + 1) / 2;
    int b_len = c_len / 2;
    if (a_size < a_len || b_size < b_len)
        return -1;
    for (int i = 0; i < c_len; ++i)
    {
        if (i % 2 == 0)
        {
            a[i / 2] = c[i] ? 1 : 0;
        }
        else
        {
            b[i / 2] = c[i] ? 1 : 0;
        }
    }
    return 0;
}

int multiplex_STDM(unsigned char *c, const int c_size,
                   const unsigned char *a, const int a_len,
                   const unsigned char *b, const int b_len)
{
    int idx = 0;
    for (int i = 0; i < std::max(a_len, b_len); ++i)
    {
        if (i < a_len && a[i] && idx < c_size)
            c[idx++] = 1;
        if (i < b_len && b[i] && idx < c_size)
            c[idx++] = 2;
    }
    return (idx <= c_size) ? 0 : -1;
}

int demultiplex_STDM(unsigned char *a, const int a_size,
                     unsigned char *b, const int b_size,
                     const unsigned char *c, const int c_len)
{
    memset(a, 0, a_size);
    memset(b, 0, b_size);

    int a_idx = 0, b_idx = 0;

    for (int i = 0; i < c_len; ++i)
    {
        if (c[i] == 1 && a_idx < a_size)
        {
            a[a_idx++] = 1;
        }
        else if (c[i] == 2 && b_idx < b_size)
        {
            b[b_idx++] = 1;
        }
    }

    if (a_idx != a_size || b_idx != b_size)
    {
        return -1;
    }
    return 0;
}

int multiplex_FDM(unsigned char *c, const int c_size,
                  const unsigned char *a, const int a_len,
                  const unsigned char *b, const int b_len)
{
    int total = a_len + b_len;
    if (c_size < total)
        return -1;
    for (int i = 0; i < a_len; ++i)
        c[i] = a[i] ? 1 : 0;
    for (int i = 0; i < b_len; ++i)
        c[a_len + i] = b[i] ? 1 : 0;
    return 0;
}

int demultiplex_FDM(unsigned char *a, const int a_size,
                    unsigned char *b, const int b_size,
                    const unsigned char *c, const int c_len)
{
    int a_len = std::min(a_size, c_len);
    for (int i = 0; i < a_len; ++i)
        a[i] = c[i] ? 1 : 0;
    int b_len = std::min(b_size, c_len - a_len);
    for (int i = 0; i < b_len; ++i)
        b[i] = c[a_len + i] ? 1 : 0;
    return 0;
}

int multiplex_CDM(unsigned char *c, const int c_size,
                  const unsigned char *a, const int a_len,
                  const unsigned char *b, const int b_len)
{
    int max_len = std::max(a_len, b_len);
    if (c_size < 2 * max_len)
        return -1;
    for (int i = 0; i < max_len; ++i)
    {
        unsigned char a_val = (i < a_len && a[i]) ? 1 : 0;
        unsigned char b_val = (i < b_len && b[i]) ? 1 : 0;
        c[2 * i] = a_val + b_val;
        c[2 * i + 1] = a_val - b_val + 1;
    }
    return 0;
}

int demultiplex_CDM(unsigned char *a, const int a_size,
                    unsigned char *b, const int b_size,
                    const unsigned char *c, const int c_len)
{
    int blocks = c_len / 2;
    for (int i = 0; i < blocks; ++i)
    {
        if (2 * i + 1 >= c_len)
            break;
        int sum_a = c[2 * i] + (c[2 * i + 1] - 1);
        int sum_b = c[2 * i] - (c[2 * i + 1] - 1);
        if (i < a_size)
            a[i] = (sum_a >= 1) ? 1 : 0;
        if (i < b_size)
            b[i] = (sum_b >= 1) ? 1 : 0;
    }
    return 0;
}

void printArray(const char *name, const unsigned char *arr, int len)
{
    std::cout << name << ": ";
    for (int i = 0; i < len; ++i)
    {
        std::cout << (int)arr[i] << " ";
    }
    std::cout << std::endl;
}

void testMultiplexDemultiplex(const char *method,
                              int (*multiplexFunc)(unsigned char *, int, const unsigned char *, int, const unsigned char *, int),
                              int (*demultiplexFunc)(unsigned char *, int, unsigned char *, int, const unsigned char *, int))
{
    std::cout << "Testing " << method << "..." << std::endl;

    unsigned char a[] = {1, 0, 1, 0, 1};
    unsigned char b[] = {0, 1, 0, 1, 0};
    int a_len = sizeof(a) / sizeof(a[0]);
    int b_len = sizeof(b) / sizeof(b[0]);

    printArray("Original A", a, a_len);
    printArray("Original B", b, b_len);

    int c_size = 2 * std::max(a_len, b_len);
    unsigned char *c = new unsigned char[c_size];
    memset(c, 0, c_size);

    if (multiplexFunc(c, c_size, a, a_len, b, b_len) != 0)
    {
        std::cerr << "Multiplex failed!" << std::endl;
        delete[] c;
        return;
    }
    printArray("Multiplexed C", c, c_size);

    unsigned char *a_out = new unsigned char[a_len];
    unsigned char *b_out = new unsigned char[b_len];
    memset(a_out, 0, a_len);
    memset(b_out, 0, b_len);

    if (demultiplexFunc(a_out, a_len, b_out, b_len, c, c_size) != 0)
    {
        std::cerr << "Demultiplex failed!" << std::endl;
        delete[] c;
        delete[] a_out;
        delete[] b_out;
        return;
    }
    printArray("Demultiplexed A", a_out, a_len);
    printArray("Demultiplexed B", b_out, b_len);

    bool success = true;
    for (int i = 0; i < a_len; ++i)
    {
        if (a_out[i] != a[i])
        {
            success = false;
            break;
        }
    }
    for (int i = 0; i < b_len; ++i)
    {
        if (b_out[i] != b[i])
        {
            success = false;
            break;
        }
    }
    if (success)
    {
        std::cout << "Test passed!" << std::endl;
    }
    else
    {
        std::cerr << "Test failed: Demultiplexed data does not match original!" << std::endl;
    }

    delete[] c;
    delete[] a_out;
    delete[] b_out;
}

int multiplex(unsigned char *c, const int c_size,
              const unsigned char *a, const int a_len,
              const unsigned char *b, const int b_len)
{
    return multiplex_TDM(c, c_size, a, a_len, b, b_len); // exp：调用TDM的编码
}

int demultiplex(unsigned char *a, const int a_size,
                unsigned char *b, const int b_size,
                const unsigned char *c, const int c_len)
{
    return demultiplex_TDM(a, a_size, b, b_size, c, c_len); // exp：调用TDM的解码
}

//
/*
int main()
{
    testMultiplexDemultiplex("TDM", multiplex_TDM, demultiplex_TDM);

    testMultiplexDemultiplex("STDM", multiplex_STDM, demultiplex_STDM);

    testMultiplexDemultiplex("FDM", multiplex_FDM, demultiplex_FDM);

    testMultiplexDemultiplex("CDM", multiplex_CDM, demultiplex_CDM);

    return 0;
}*/